// What is this?

// 在 JavaScript 中，this关键字指的是当前正在执行代码的对象。
// this评估结果的简短版本如下：

// · 默认情况下，this指的是全局对象。
// · 在函数中，当非严格模式时，this指的是全局对象。
// · 在函数中，在严格模式下，this是undefined。
// · 在箭头函数中，this保留封闭词法上下文的this。
// · 在对象方法中，this指的是调用该方法的对象。
// · 在构造函数调用中，this绑定到正在构造的新对象。
// · 在事件处理程序中，this绑定到放置侦听器的元素。





// Global context
// 在全局执行上下文中，this指的是全局对象。

console.log(this === window); // true





// Function context
// 当不在严格模式下时，函数this引用全局对象。
function f() {
  return this;
}

console.log(f() === window); // true


// 在严格模式下，
// 在进入执行上下文时未设置时函数this为undefined。
'use strict';

function f() {
  return this;
}

console.log(f()); // undefined





// Object context
// 当作为对象的方法被调用时，
// this指的是调用该方法的对象。
// 这适用于在对象原型链中任何地方定义的方法
// （即自己的和继承的方法）。
const obj = {
  f: function() {
    return this;
  }
};

const myObj = Object.create(obj);
myObj.foo = 1;
console.log(myObj.f()); // { foo: 1 }

// 类似地，在构造函数中使用时，
// this指的是正在构造的对象。
class C {
  constructor() {
    this.x = 10;
  }
}
const obj = new C();
console.log(obj.x); // 10






// Arrow function context (箭头函数上下文)
// 在箭头函数中，this保留封闭词法上下文的this.

const f = () => this;

console.log(f() === window); // true

const obj = {
  foo: function() {
    const baz = () => this;
    return baz();
  },
  bar: () => this
};

console.log(obj.foo()); // { foo, bar }
console.log(obj.bar() === window); // true
// 请注意在第二个示例中，
// 箭头函数this指向全局对象，
// 除非包含在一个function调用中，
// 它的this指向调用它的对象，，
// 并且箭头函数保留了其上下文。






// Event handler context 事件处理程序上下文
// 在事件处理程序中使用时，this指的是放置侦听器的元素。

const el = document.getElementById('my-el');

el.addEventListener('click', function() {
  console.log(this === el); // true
});






// Binding 绑定 this
// 使用 Function.prototype.bind()
// 从现有函数返回一个新函数，
// 它被永久地绑定到bind()的第一个参数。
function f() {
  return this.foo;
}

var x = f.bind({foo: 'hello'});
console.log(x()); // 'hello'

// 类似地，
// 使用 Function.prototype.call() 
// 或 Function.prototype.apply()
// 将被调用函数的this绑定到这两个函数的第一个参数。

function f() {
  return this.foo;
}

console.log(f.call({foo: 'hi'})); // 'hi'